use std::fs;
use std::path::{Path, PathBuf};
use anyhow::Result;
use log::{debug, info, warn};
use walkdir::WalkDir;

use crate::errors::{ConversionError, ConversionWarnings, ResultExt};
use crate::project::Project;

/// 处理文件复制操作的模块
pub struct FileCopier {
    input_dir: PathBuf,
    warnings: ConversionWarnings,
}

impl FileCopier {
    pub fn new(input_dir: &Path) -> Self {
        Self {
            input_dir: input_dir.to_path_buf(),
            warnings: ConversionWarnings::new(),
        }
    }

    /// 复制项目文件到输出目录
    pub fn copy_project_files(&mut self, project: &Project, output_dir: &Path) -> Result<()> {
        info!("复制项目文件到输出目录");
        
        // 创建输出目录（如果不存在）
        fs::create_dir_all(output_dir)
            .with_context(|| format!("无法创建输出目录: {}", output_dir.display()))?;
        
        // 获取项目根目录
        let project_dir = if let Some(vcxproj_path) = self.find_files(&self.input_dir, ".vcxproj").first() {
            vcxproj_path.parent().unwrap_or(&self.input_dir).to_path_buf()
        } else {
            self.input_dir.clone()
        };
        
        // 复制源文件
        for source in &project.source_files {
            if let Err(e) = self.copy_single_file(source, &project_dir, output_dir) {
                warn!("复制源文件 {} 失败: {}", source, e);
                self.warnings.add_missing_file(Path::new(source).to_path_buf());
            }
        }
        
        // 复制头文件
        for header in &project.header_files {
            if let Err(e) = self.copy_single_file(header, &project_dir, output_dir) {
                warn!("复制头文件 {} 失败: {}", header, e);
                self.warnings.add_missing_file(Path::new(header).to_path_buf());
            }
        }
        
        // 复制Qt资源文件
        for resource in &project.resources {
            if let Err(e) = self.copy_single_file(resource, &project_dir, output_dir) {
                warn!("复制Qt资源文件 {} 失败: {}", resource, e);
                self.warnings.add_missing_file(Path::new(resource).to_path_buf());
            }
        }
        
        // 复制Qt界面文件
        for form in &project.forms {
            if let Err(e) = self.copy_single_file(form, &project_dir, output_dir) {
                warn!("复制Qt界面文件 {} 失败: {}", form, e);
                self.warnings.add_missing_file(Path::new(form).to_path_buf());
            }
        }
        
        // 报告任何警告
        if self.warnings.has_warnings() {
            info!("文件复制完成，但有 {} 个文件未找到", self.warnings.missing_files.len());
        } else {
            info!("所有文件复制成功");
        }
        
        Ok(())
    }

    /// 获取警告信息
    pub fn get_warnings(&self) -> &ConversionWarnings {
        &self.warnings
    }

    /// 复制单个文件，处理路径问题
    fn copy_single_file(&mut self, file_path_str: &str, project_dir: &Path, output_dir: &Path) -> Result<()> {
        let file_path = project_dir.join(file_path_str);
        
        if file_path.exists() {
            // 创建目标文件所在的目录结构
            if let Some(parent) = output_dir.join(file_path_str).parent() {
                fs::create_dir_all(parent)
                    .with_context(|| format!("无法创建目录: {}", parent.display()))?;
            }
            
            let dest_path = output_dir.join(file_path_str);
            match fs::copy(&file_path, &dest_path) {
                Ok(_) => {
                    debug!("已复制文件: {} -> {}", file_path.display(), dest_path.display());
                    Ok(())
                },
                Err(e) => {
                    let error = ConversionError::FileCopyFailed(
                        file_path.clone(),
                        dest_path,
                        e.to_string()
                    );
                    Err(error.into())
                }
            }
        } else {
            warn!("文件未找到: {}, 尝试备用位置", file_path.display());
            self.copy_file_with_fallback(file_path_str, project_dir, output_dir)
        }
    }

    /// 尝试在备用位置查找并复制文件
    fn copy_file_with_fallback(&mut self, file_path: &str, project_dir: &Path, output_dir: &Path) -> Result<()> {
        // 尝试不同的相对路径组合
        let possible_locations = vec![
            self.input_dir.join(file_path),
            project_dir.join("..").join(file_path),
            project_dir.join("../..").join(file_path),
        ];
        
        for location in possible_locations {
            if location.exists() {
                // 创建目标文件所在的目录结构
                if let Some(parent) = output_dir.join(file_path).parent() {
                    fs::create_dir_all(parent)
                        .with_context(|| format!("无法创建目录: {}", parent.display()))?;
                }
                
                let dest_path = output_dir.join(file_path);
                match fs::copy(&location, &dest_path) {
                    Ok(_) => {
                        debug!("已从备用位置复制文件: {} -> {}", location.display(), dest_path.display());
                        return Ok(());
                    },
                    Err(e) => {
                        warn!("无法复制文件 {} -> {}: {}", location.display(), dest_path.display(), e);
                        self.warnings.add_path_issue(format!(
                            "无法从备用位置 {} 复制到 {}: {}", 
                            location.display(), dest_path.display(), e
                        ));
                    }
                }
            }
        }
        
        // 尝试搜索具有相同文件名的文件
        let file_name = Path::new(file_path)
            .file_name()
            .map(|n| n.to_string_lossy().to_string());
        
        if let Some(name) = file_name {
            debug!("搜索文件名为 {} 的文件", name);
            let name_matches = self.find_files_by_name(&self.input_dir, &name);
            
            if !name_matches.is_empty() {
                debug!("找到 {} 个匹配的文件", name_matches.len());
                // 使用第一个匹配项
                let alt_path = &name_matches[0];
                
                // 创建目标文件所在的目录结构
                if let Some(parent) = output_dir.join(file_path).parent() {
                    fs::create_dir_all(parent)
                        .with_context(|| format!("无法创建目录: {}", parent.display()))?;
                }
                
                let dest_path = output_dir.join(file_path);
                match fs::copy(alt_path, &dest_path) {
                    Ok(_) => {
                        debug!("已复制匹配文件: {} -> {}", alt_path.display(), dest_path.display());
                        self.warnings.add_path_issue(format!(
                            "使用替代路径 {} 替代原始路径 {}", 
                            alt_path.display(), file_path
                        ));
                        return Ok(());
                    },
                    Err(e) => {
                        warn!("无法复制文件 {} -> {}: {}", alt_path.display(), dest_path.display(), e);
                        self.warnings.add_path_issue(format!(
                            "尝试使用替代文件，但复制失败 {} -> {}: {}", 
                            alt_path.display(), dest_path.display(), e
                        ));
                    }
                }
            }
        }
        
        // 如果所有尝试都失败，返回错误
        self.warnings.add_missing_file(Path::new(file_path).to_path_buf());
        Err(ConversionError::FileNotFound(Path::new(file_path).to_path_buf()).into())
    }

    /// 递归查找具有特定扩展名的文件
    pub fn find_files(&self, dir: &Path, extension: &str) -> Vec<PathBuf> {
        let mut results = Vec::new();
        
        let walker = WalkDir::new(dir).into_iter();
        for entry in walker.filter_map(|e| e.ok()) {
            let path = entry.path();
            if path.is_file() && path.extension().map_or(false, |ext| ext == &extension[1..]) {
                results.push(path.to_path_buf());
            }
        }
        
        results
    }
    
    /// 按文件名查找文件
    pub fn find_files_by_name(&self, dir: &Path, filename: &str) -> Vec<PathBuf> {
        let mut results = Vec::new();
        
        let walker = WalkDir::new(dir).into_iter();
        for entry in walker.filter_map(|e| e.ok()) {
            let path = entry.path();
            if path.is_file() && path.file_name().map_or(false, |name| name.to_string_lossy() == filename) {
                results.push(path.to_path_buf());
            }
        }
        
        results
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_find_files() {
        // 创建临时目录和文件以测试find_files函数
        let temp_dir = std::env::temp_dir();
        let test_file = temp_dir.join("test.vcxproj");
        if !test_file.exists() {
            let mut file = std::fs::File::create(&test_file).unwrap();
            std::io::Write::write_all(&mut file, b"<Project></Project>").unwrap();
        }
        
        let copier = FileCopier::new(&temp_dir);
        let files = copier.find_files(&temp_dir, ".vcxproj");
        
        // 清理临时文件
        if test_file.exists() {
            std::fs::remove_file(&test_file).unwrap_or(());
        }
        
        // 如果找到了文件，验证它是我们创建的文件
        if !files.is_empty() {
            assert!(files.iter().any(|f| f.ends_with("test.vcxproj")));
        }
    }
} 